using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using CoreLibrary.Paging;
using CoreLibrary.Repo;
using Entities.DataBase.Obj;
using Entities.DataBase.Persistent;
using Entities.Enumeration;

namespace Entities.DataBase.Impl {
    
    public class UserRepository : BaseRepository<User>, IUserRepository {

        private static readonly Func<DataContext, string, User> LinqGetAccountByEmail
            = CompiledQuery.Compile((DataContext context, string email) =>
                      context.GetTable<User>()
                             .SingleOrDefault(account => account.Email.Equals(email)));

        private static readonly Func<DataContext, string, User> LinqGetAccountByUserId
            = CompiledQuery.Compile((DataContext context, string userId) => 
                      context.GetTable<User>()
                             .SingleOrDefault(account => account.UserId.Equals(userId)));

        private static readonly Func<DataContext, string, User> LinqGetAccountByLogInName
            = CompiledQuery.Compile((DataContext context, string loginName) =>
                      context.GetTable<User>()
                             .SingleOrDefault(account => account.LogInName.Equals(loginName)));

        private static readonly Func<DataContext, IQueryable<UserInfo>> LinqGetUserInfos
            = CompiledQuery.Compile((DataContext context) =>
                      context.GetTable<User>().Where(u => u.UserRole != UserRole.SUPER).Select(u => new UserInfo {
                          UserId = u.UserId,
                          CName  = u.FullName,
                          Name   = u.FullName,
                          Email  = u.Email,
                          Role   = u.UserRole
                      }));


        public override string TableName {
            get {
                return "D_USER";
            }
        }

        public List<User> List() {
            return GetAll();
        }

        public List<User> List(PagingRequest request) {
            return GetMany(request);
        }

        public List<UserInfo> ListInfos() {
            return Execute(context => LinqGetUserInfos(context).ToList());
        }

        public User Get(string accountId) {
            return Execute(context => LinqGetAccountByUserId(context, accountId));
        }

        public User GetByEmail(string email) {
            return Execute(context => LinqGetAccountByEmail(context, email));
        }

        public User GetByLogInName(string name) {
            return Execute(context=> LinqGetAccountByLogInName(context, name));
        }

        public void Delete(string accountId) {
            Execute((context, transaction) => {
                var account = LinqGetAccountByUserId(context, accountId);
                if (account == null) {
                    transaction.Complete();
                    return;
                }

                context.GetTable<User>().DeleteOnSubmit(account);
                context.SubmitChanges();
                transaction.Complete();
            });
        }

        public void Create(User account) {
            Execute((context, transaction) => {
                var accountByID = LinqGetAccountByUserId(context, account.UserId);
                if (accountByID != null) {
                    throw new ArgumentException("Account already exist.");
                }

                var accountByEmail = LinqGetAccountByEmail(context, account.Email);
                if (accountByEmail != null) {
                    throw new ArgumentException("Email already exist.");
                }
               
                context.GetTable<User>().InsertOnSubmit(account);
                context.SubmitChanges();
                transaction.Complete();
            });
        }
        
    }

}